﻿using System.Reflection;
using System.Text.RegularExpressions;

namespace Leo.Common
{
    public abstract class Enumeration : IConvertible, ICloneable, IComparable
    {
        internal int Value { get; set; }

        internal string Name { get; set; }

        internal Dictionary<string, string> Descriptions { get; set; }

        TypeCode IConvertible.GetTypeCode()
        {
            return TypeCode.String;
        }

        bool IConvertible.ToBoolean(IFormatProvider provider)
        {
            return this.Value != 0;
        }

        byte IConvertible.ToByte(IFormatProvider provider)
        {
            if (this.Value > 255)
            {
                throw new OverflowException();
            }
            return Convert.ToByte(this.Value, provider);
        }

        char IConvertible.ToChar(IFormatProvider provider)
        {
            if (this.Value > 65535)
            {
                throw new OverflowException();
            }
            return Convert.ToChar(this.Value, provider);
        }

        DateTime IConvertible.ToDateTime(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        decimal IConvertible.ToDecimal(IFormatProvider provider)
        {
            return Convert.ToDecimal(this.Value, provider);
        }

        double IConvertible.ToDouble(IFormatProvider provider)
        {
            return Convert.ToDouble(this.Value, provider);
        }

        short IConvertible.ToInt16(IFormatProvider provider)
        {
            if (this.Value > 32767)
            {
                throw new OverflowException();
            }
            return Convert.ToInt16(this.Value, provider);
        }

        int IConvertible.ToInt32(IFormatProvider provider)
        {
            return Convert.ToInt32(this.Value, provider);
        }

        long IConvertible.ToInt64(IFormatProvider provider)
        {
            return Convert.ToInt64(this.Value, provider);
        }

        sbyte IConvertible.ToSByte(IFormatProvider provider)
        {
            if (this.Value > 127)
            {
                throw new OverflowException();
            }
            return Convert.ToSByte(this.Value, provider);
        }

        float IConvertible.ToSingle(IFormatProvider provider)
        {
            if ((float)this.Value > 3.4028235E+38f)
            {
                throw new OverflowException();
            }
            return Convert.ToSingle(this.Value, provider);
        }

        string IConvertible.ToString(IFormatProvider provider)
        {
            return this.Name;
        }

        object IConvertible.ToType(Type conversionType, IFormatProvider provider)
        {
            if (conversionType == typeof(string))
            {
                return this.Name.ToString(provider);
            }
            if (conversionType == typeof(int) || conversionType == typeof(long) || conversionType == typeof(decimal) || conversionType == typeof(int?) || conversionType == typeof(long?))
            {
                return Convert.ChangeType(this.Value, conversionType, provider);
            }
            if (conversionType.IsAssignableFrom(base.GetType()))
            {
                return this;
            }
            throw new InvalidCastException();
        }

        ushort IConvertible.ToUInt16(IFormatProvider provider)
        {
            if (this.Value > 65535)
            {
                throw new OverflowException();
            }
            return Convert.ToUInt16(this.Value, provider);
        }

        uint IConvertible.ToUInt32(IFormatProvider provider)
        {
            return Convert.ToUInt32(this.Value, provider);
        }

        ulong IConvertible.ToUInt64(IFormatProvider provider)
        {
            return Convert.ToUInt64(this.Value, provider);
        }

        public static bool operator ==(Enumeration left, Enumeration right)
        {
            return (object.Equals(left, null) && object.Equals(right, null)) || (!object.Equals(left, null) && left.Equals(right));
        }

        public static bool operator !=(Enumeration left, Enumeration right)
        {
            return !(left == right);
        }

        private static string GetNames(int id, Type objectType)
        {
            IEnumerable<Enumeration> all = Enumeration.GetAll(objectType);
            List<string> list = new List<string>();
            foreach (Enumeration enumeration in all)
            {
                if ((enumeration.Value & id) == enumeration.Value)
                {
                    list.Add(enumeration.Name);
                }
            }
            return string.Join(",", list);
        }

        private static Dictionary<string, string> GetDescriptions(int id, Type objectType)
        {
            IEnumerable<Enumeration> all = Enumeration.GetAll(objectType);
            Dictionary<string, string> dictionary = new Dictionary<string, string>();
            foreach (Enumeration enumeration in all)
            {
                if ((enumeration.Value & id) == enumeration.Value)
                {
                    foreach (KeyValuePair<string, string> keyValuePair in enumeration.Descriptions)
                    {
                        string text;
                        dictionary[keyValuePair.Key] = (dictionary.TryGetValue(keyValuePair.Key, out text) ? (text + "," + keyValuePair.Value) : keyValuePair.Value);
                    }
                }
            }
            return dictionary;
        }

        public static string[] GetNames(Type objectType)
        {
            return Enumerable.ToArray<string>(Enumerable.Select<Enumeration, string>(Enumeration.GetAll(objectType), (Enumeration x) => x.Name));
        }

        public static int[] GetValues(Type objectType)
        {
            return Enumerable.ToArray<int>(Enumerable.Select<Enumeration, int>(Enumeration.GetAll(objectType), (Enumeration x) => x.Value));
        }

        public static Enumeration operator |(Enumeration left, Enumeration right)
        {
            ExceptionHelper.ThrowIfNull(left);
            ExceptionHelper.ThrowIfNull(right);
            Type type = left.GetType();
            if (type != right.GetType())
            {
                throw new ArgumentException("不同的枚举类型不支持或运算");
            }
            Enumeration enumeration = left.Clone() as Enumeration;
            enumeration.Value = (left.Value | right.Value);
            enumeration.Name = Enumeration.GetNames(enumeration.Value, type);
            enumeration.Descriptions = Enumeration.GetDescriptions(enumeration.Value, type);
            return enumeration;
        }

        public static Enumeration operator &(Enumeration left, Enumeration right)
        {
            ExceptionHelper.ThrowIfNull(left);
            ExceptionHelper.ThrowIfNull(right);
            Type type = left.GetType();
            if (type != right.GetType())
            {
                throw new ArgumentException("不同的枚举类型不支持与运算");
            }
            Enumeration enumeration = left.Clone() as Enumeration;
            enumeration.Value = (left.Value & right.Value);
            enumeration.Name = Enumeration.GetNames(enumeration.Value, type);
            enumeration.Descriptions = Enumeration.GetDescriptions(enumeration.Value, type);
            return enumeration;
        }

        public static Enumeration operator ^(Enumeration left, Enumeration right)
        {
            ExceptionHelper.ThrowIfNull(left);
            ExceptionHelper.ThrowIfNull(right);
            Type type = left.GetType();
            if (type != right.GetType())
            {
                throw new ArgumentException("不同的枚举类型不支持异或运算");
            }
            Enumeration enumeration = left.Clone() as Enumeration;
            enumeration.Value = (left.Value ^ right.Value);
            enumeration.Name = Enumeration.GetNames(enumeration.Value, type);
            enumeration.Descriptions = Enumeration.GetDescriptions(enumeration.Value, type);
            return enumeration;
        }

        public static implicit operator int(Enumeration enumeration)
        {
            return enumeration.Value;
        }

        public static implicit operator string(Enumeration enumeration)
        {
            return enumeration.Name;
        }

        public override bool Equals(object obj)
        {
            if (obj != null)
            {
                Enumeration enumeration = obj as Enumeration;
                if (enumeration != null)
                {
                    bool flag = base.GetType().Equals(obj.GetType());
                    bool flag2 = this.Value.Equals(enumeration.Value);
                    return flag && flag2;
                }
            }
            return false;
        }

        public override string ToString()
        {
            return this.Name;
        }

        public override int GetHashCode()
        {
            return this.Value.GetHashCode();
        }

        public int CompareTo(object obj)
        {
            if (obj != null)
            {
                Enumeration enumeration = obj as Enumeration;
                if (enumeration != null)
                {
                    return this.Value.CompareTo(enumeration.Value);
                }
            }
            return -1;
        }

        public object Clone()
        {
            Type type = base.GetType();
            ParameterInfo[] parameters = Enumerable.First<ConstructorInfo>(type.GetConstructors()).GetParameters();
            object[] array = new object[(parameters != null) ? parameters.Length : 0];
            for (int i = 0; i < array.Length; i++)
            {
                ParameterInfo parameterInfo = parameters[i];
                if (parameterInfo.ParameterType == typeof(int))
                {
                    array[i] = 0;
                }
                else if (parameterInfo.ParameterType == typeof(string))
                {
                    array[i] = string.Empty;
                }
                else
                {
                    array[i] = null;
                }
            }
            object obj = Activator.CreateInstance(type, array);
            Enumeration enumeration = obj as Enumeration;
            enumeration.Value = this.Value;
            enumeration.Name = this.Name;
            enumeration.Descriptions = (Dictionary<string, string>)this.Descriptions.Clone<string, string>();
            return obj;
        }

        public string GetDescription(string scene = null)
        {
            string result;
            if (this.Descriptions.TryGetValue(scene ?? "default", ref result))
            {
                return result;
            }
            return null;
        }

        public static IEnumerable<T> GetAll<T>() where T : Enumeration<T>
        {
            return Enumerable.Cast<T>(Enumerable.Select<FieldInfo, object>(typeof(T).GetFields(26), (FieldInfo f) => f.GetValue(null)));
        }

        public static IEnumerable<Enumeration> GetAll(Type t)
        {
            return Enumerable.Cast<Enumeration>(Enumerable.Select<FieldInfo, object>(t.GetFields(26), (FieldInfo f) => f.GetValue(null)));
        }

        private static object Parse(string s, Type objectType)
        {
            ExceptionHelper.ThrowIfNull(objectType);
            IEnumerable<Enumeration> all = Enumeration.GetAll(objectType);
            string[] array = s.Split(',', 0);
            List<Enumeration> list = new List<Enumeration>();
            Func<Enumeration, bool> <> 9__0;
            foreach (string text in array)
            {
                IEnumerable<Enumeration> enumerable = all;
                Func<Enumeration, bool> func;
                if ((func = <> 9__0) == null)
                {
                    func = (<> 9__0 = ((Enumeration x) => x.ToString() == s));
                }
                Enumeration enumeration = Enumerable.FirstOrDefault<Enumeration>(enumerable, func);
                if (enumeration != null)
                {
                    list.Add(enumeration);
                }
            }
            Enumeration enumeration2 = null;
            foreach (Enumeration enumeration3 in list)
            {
                enumeration2 = ((enumeration2 == null) ? enumeration3 : (enumeration2 | enumeration3));
            }
            return enumeration2;
        }

        private static object Parse(int id, Type objectType)
        {
            IEnumerable<Enumeration> all = Enumeration.GetAll(objectType);
            Enumeration enumeration = Enumerable.FirstOrDefault<Enumeration>(all, (Enumeration x) => x.Value == id);
            if (enumeration != null)
            {
                return enumeration;
            }
            List<Enumeration> list = new List<Enumeration>();
            Func<Enumeration, bool> <> 9__1;
            foreach (Enumeration enumeration2 in all)
            {
                enumeration2;
                IEnumerable<Enumeration> enumerable = all;
                Func<Enumeration, bool> func;
                if ((func = <> 9__1) == null)
                {
                    func = (<> 9__1 = ((Enumeration x) => (x.Value & id) == x.Value));
                }
                Enumeration enumeration3 = Enumerable.FirstOrDefault<Enumeration>(enumerable, func);
                if (enumeration3 != null)
                {
                    list.Add(enumeration3);
                }
            }
            Enumeration enumeration4 = null;
            foreach (Enumeration enumeration5 in list)
            {
                enumeration4 = ((enumeration4 == null) ? enumeration5 : (enumeration4 | enumeration5));
            }
            return enumeration4;
        }

        public static object Parse(object s, Type objectType)
        {
            ExceptionHelper.ThrowIfNull(s);
            ExceptionHelper.ThrowIfNull(objectType);
            if (!Enumeration.IsAssignableFrom(objectType))
            {
                throw new ArgumentException("指定转换的类型不是Enumeration");
            }
            if (s.GetType() == typeof(int))
            {
                return Enumeration.Parse(Convert.ToInt32(s), objectType);
            }
            string text = s.ToString();
            if (Regex.IsMatch(text, "^\\d+$"))
            {
                return Enumeration.Parse(Convert.ToInt32(s), objectType);
            }
            return Enumeration.Parse(text, objectType);
        }

        public static T Parse<T>(object s)
        {
            return (T)((object)Enumeration.Parse(s, typeof(T)));
        }

        public static bool IsAssignableFrom(Type enumerationType)
        {
            return typeof(Enumeration).IsAssignableFrom(enumerationType);
        }
    }

    public abstract class Enumeration<T> : Enumeration where T : Enumeration<T>
    {
        protected Enumeration(int id, string name)
        {
            base.Value = id;
            base.Name = name;
            base.Descriptions = new Dictionary<string, string>();
        }

        protected Enumeration(int id, string name, string description) : this(id, name)
        {
            base.Descriptions.Add("default", description);
        }

        protected Enumeration(int id, string name, params KeyValuePair<string, string>[] descriptions) : this(id, name)
        {
            if (descriptions != null)
            {
                foreach (KeyValuePair<string, string> keyValuePair in descriptions)
                {
                    base.Descriptions[keyValuePair.Key] = keyValuePair.Value;
                }
            }
        }

        public static IEnumerable<T> GetAll()
        {
            return Enumeration.GetAll<T>();
        }

        public string[] GetNames()
        {
            return Enumerable.ToArray<string>(Enumerable.Select<T, string>(Enumeration<T>.GetAll(), (T x) => x.Name));
        }

        public int[] GetValues()
        {
            return Enumerable.ToArray<int>(Enumerable.Select<T, int>(Enumeration<T>.GetAll(), (T x) => x.Value));
        }
    }
}
